﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;

namespace MapControlSample
{
    public partial class USMapControl : UserControl
    {
        public List<State> States;
        public Color HeatColor;
        public Color RollOverColor;
        public delegate void StateClickDelegate(Path pathState, State state);
        public StateClickDelegate StateClickCallback;
        public string NumberFormat = "#,#";
        public string CurrencySymbol = "";

        private double _stateLow;
        private double _stateHigh;

        public USMapControl()
        {
            InitializeComponent();
        }
        public void Update()
        {
            //Get the upper and lower values for the States
            var result = (from s in States
                          select s.Value).Max();
            _stateHigh = result;

            var lowResult = (from s in States
                             select s.Value).Min();
            _stateLow = lowResult;

            UpdateScale(_stateHigh, _stateLow);


            /* Update Map*/
            foreach (UIElement uie in Map.Children)
            {
                if (uie.GetType().ToString() == "System.Windows.Shapes.Path")
                {
                    Path state = (Path)uie;
                    var stateResult = from s in States
                                      where s.Name == state.Name.Substring(0, 2)
                                      select s;
                    foreach (State thisState in stateResult)
                    {
                        FillInStateColor(state, _stateHigh, _stateLow, thisState);
                    }
                }
            }
        }

        private void UpdateScale(double stateHigh, double stateLow)
        {
            double span = stateHigh - stateLow;

            string strLow = NumberToShortenedString(stateLow);
            string strHigh = NumberToShortenedString(stateHigh);

            lblMinScale.Text = strLow;
            lblMaxScale.Text = strHigh;
            foreach (UIElement scaleSeg in Scale.Children)
            {
                switch (scaleSeg.GetType().ToString())
                {
                    case "System.Windows.Shapes.Path":
                        Path scalePath = (Path)scaleSeg;
                        string scaleNumStr = scalePath.Name.Substring(scalePath.Name.IndexOf("_") + 1);
                        int scaleNum = Convert.ToInt32(scaleNumStr);
                        double bottomRange = stateLow + (span * ((scaleNum - 1) * 0.1));
                        double topRange = stateLow + (span * (scaleNum * 0.1));
                        byte opacity = Convert.ToByte(scaleNum * 25);
                        HeatColor.A = opacity;
                        scalePath.Fill = new SolidColorBrush(HeatColor);
                        scalePath.Tag = NumberToShortenedString(bottomRange) + " - " + NumberToShortenedString(topRange);

                        break;
                    case "System.Windows.Shapes.Rectangle":
                        
                        Rectangle scaleRectPath = (Rectangle)scaleSeg;
                        if (scaleRectPath.Name.Contains("_"))
                        {
                            string scaleRectNumStr = scaleRectPath.Name.Substring(scaleRectPath.Name.IndexOf("_") + 1);
                            int scaleRectNum = Convert.ToInt32(scaleRectNumStr);
                            double bottomRectRange = stateLow + (span * ((scaleRectNum - 1) * 0.1));
                            double topRectRange = stateLow + (span * (scaleRectNum * 0.1));
                            byte opacityRect = Convert.ToByte(scaleRectNum * 25);
                            HeatColor.A = opacityRect;
                            scaleRectPath.Fill = new SolidColorBrush(HeatColor);
                            scaleRectPath.Tag = NumberToShortenedString(bottomRectRange) + " - " + NumberToShortenedString(topRectRange);
                        }
                        break;

                }
            }
        }


        #region HELPER METHODS
        private string NumberToShortenedString(double theNumber)
        {

            if (theNumber > 1000000000)
            {
                return CurrencySymbol + (theNumber / 1000000000).ToString("#,#.00B");
            }
            if (theNumber > 1000000)
            {
                return CurrencySymbol + (theNumber / 1000000).ToString("#,#.00M");
            }
            if (theNumber > 1000)
            {
                return CurrencySymbol + (theNumber / 1000).ToString("#,#K");
            }
            else
            {
                return CurrencySymbol + theNumber.ToString("#,#");
            }
        }
        private void FillInStateColor(Path state, double StateHigh, double StateLow, State thisState)
        {
            state.Tag = thisState;
            int score = GetRangeScore(StateHigh, StateLow, thisState.Value);

            if (HeatColor == null)
            {
                HeatColor = new Color();
                HeatColor.R = 255;
            }


            byte opacity = Convert.ToByte(score * 25);
            HeatColor.A = opacity;
            state.Fill = new SolidColorBrush(HeatColor);
        }
        private int GetRangeScore(double high, double low, double testValue)
        {
            double increment = (high - low) / 10;
            int rtnValue = 0;
            for (int i = 0; i < 10; i++)
            {
                if ((low + (increment * i) <= testValue) && (testValue <= (low + (increment * (i + 1)))))
                {
                    rtnValue = i + 1;
                    i = 10;

                }
            }

            return rtnValue;
        }
        #endregion

        #region EVENTS
        private void ScaleSeg_MouseEnter(object sender, MouseEventArgs e)
        {
            switch (sender.GetType().ToString())
            {
                case "System.Windows.Shapes.Path":
                    Path scalePath = (Path)sender;
                    lblHoverSpan.Text = scalePath.Tag.ToString();
                    break;
                case "System.Windows.Shapes.Rectangle":
                    Rectangle scaleRectPath = (Rectangle)sender;
                    lblHoverSpan.Text = scaleRectPath.Tag.ToString();
                    break;
            }
        }
        private void ScaleSeg_MouseLeave(object sender, MouseEventArgs e)
        {
            lblHoverSpan.Text = "";
        }
        private void State_MouseEnter(object sender, MouseEventArgs e)
        {
            Path pathState = (Path)sender;
            State theState = (State)pathState.Tag;

            if (theState.Name.StartsWith("MI"))
            {
                MI_1.Fill = new SolidColorBrush(RollOverColor);
                MI_2.Fill = new SolidColorBrush(RollOverColor);
            }
            else if (theState.Name.StartsWith("HI"))
            {
                HI_1.Fill = new SolidColorBrush(RollOverColor);
                HI_2.Fill = new SolidColorBrush(RollOverColor);
                HI_3.Fill = new SolidColorBrush(RollOverColor);
                HI_4.Fill = new SolidColorBrush(RollOverColor);
                HI_5.Fill = new SolidColorBrush(RollOverColor);
                HI_6.Fill = new SolidColorBrush(RollOverColor);
            }
            else
            {
                pathState.Fill = new SolidColorBrush(RollOverColor);
            }

            txtStatePopup.Opacity = 1;
            txtStatePopup.Background = new SolidColorBrush(RollOverColor);
            string strStateValue = theState.Value.ToString(NumberFormat);
            txtStatePopup.Width = strStateValue.Length * 14;
            txtStatePopup.Text = theState.Name + ": " + strStateValue;

            Point point = e.GetPosition(LayoutRoot);
            Canvas.SetLeft(txtStatePopup, point.X);
            Canvas.SetTop(txtStatePopup, point.Y - 70);
        }
        private void State_MouseLeave(object sender, MouseEventArgs e)
        {
            Path pathState = (Path)sender;
            State theState = (State)pathState.Tag;

            double StateHigh = _stateHigh;
            double StateLow = _stateLow;

            if (theState.Name.StartsWith("MI"))
            {
                FillInStateColor(MI_1, Convert.ToDouble(StateHigh), Convert.ToDouble(StateLow), theState);
                FillInStateColor(MI_2, Convert.ToDouble(StateHigh), Convert.ToDouble(StateLow), theState);
            }
            else if (theState.Name.StartsWith("HI"))
            {
                FillInStateColor(HI_1, Convert.ToDouble(StateHigh), Convert.ToDouble(StateLow), theState);
                FillInStateColor(HI_2, Convert.ToDouble(StateHigh), Convert.ToDouble(StateLow), theState);
                FillInStateColor(HI_3, Convert.ToDouble(StateHigh), Convert.ToDouble(StateLow), theState);
                FillInStateColor(HI_4, Convert.ToDouble(StateHigh), Convert.ToDouble(StateLow), theState);
                FillInStateColor(HI_5, Convert.ToDouble(StateHigh), Convert.ToDouble(StateLow), theState);
                FillInStateColor(HI_6, Convert.ToDouble(StateHigh), Convert.ToDouble(StateLow), theState);
            }
            else
            {
                FillInStateColor(pathState, Convert.ToDouble(StateHigh), Convert.ToDouble(StateLow), theState);
            }

            txtStatePopup.Text = "";
            txtStatePopup.Opacity = 0;
        }
        private void State_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            Path pathState = (Path)sender;
            State theState = (State)pathState.Tag;

            if (StateClickCallback != null)
            {
                StateClickCallback(pathState, theState);
            }


            //if (isStateScaledUp)
            //{
            //    GreyOutRect.Width = 1;
            //    GreyOutRect.Height = 1;
            //    GreyOutRect.Opacity = 0;
            //    isStateScaledUp = false;
            //    ScaleTransform scaleTransform = new ScaleTransform();
            //    scaleTransform.ScaleX = 1;
            //    scaleTransform.ScaleY = 1;
            //    scaledUpState.RenderTransform = scaleTransform;
            //}
            //else
            //{
            //    scaledUpState = pathState;
            //    isStateScaledUp = true;
            //    ScaleTransform scaleTransform = new ScaleTransform();
            //    scaleTransform.ScaleX = 2;
            //    scaleTransform.ScaleY = 2;
            //    pathState.RenderTransform = scaleTransform;
            //}


        }
        #endregion

        
    }



    public class State
    {
        private string _Name;
        private double _Value;
        private string _Color;

        public string Name
        {
            set
            {
                _Name = value;
            }
            get
            {
                return _Name;
            }
        }
        public double Value
        {
            set
            {
                _Value = value;
            }
            get
            {
                return _Value;
            }
        }
        public string Color
        {
            set
            {
                _Color = value;
            }
            get
            {
                return _Color;
            }
        }

        public State()
        {
        }
        public State(string name, double value)
        {
            _Name = name;
            _Value = value;
        }
        public State(string name, double inValue, string color)
        {
            _Name = name;
            _Value = inValue;
            _Color = color;
        }


    }


    public static class SilverlightExtensions
    {

        public static T Clone<T>(T source)
        {

            T cloned = (T)Activator.CreateInstance(source.GetType());



            foreach (PropertyInfo curPropInfo in source.GetType().GetProperties())
            {

                if (curPropInfo.GetGetMethod() != null

                    && (curPropInfo.GetSetMethod() != null))
                {

                    // Handle Non-indexer properties

                    if (curPropInfo.Name != "Item")
                    {

                        // get property from source

                        object getValue = curPropInfo.GetGetMethod().Invoke(source, new object[] { });



                        // clone if needed

                        if (getValue != null && getValue is DependencyObject)

                            getValue = Clone((DependencyObject)getValue);



                        // set property on cloned

                        curPropInfo.GetSetMethod().Invoke(cloned, new object[] { getValue });

                    }

                        // handle indexer

                    else
                    {

                        // get count for indexer

                        int numberofItemInColleciton =

                            (int)

                            curPropInfo.ReflectedType.GetProperty("Count").GetGetMethod().Invoke(source, new object[] { });



                        // run on indexer

                        for (int i = 0; i < numberofItemInColleciton; i++)
                        {

                            // get item through Indexer

                            object getValue = curPropInfo.GetGetMethod().Invoke(source, new object[] { i });



                            // clone if needed

                            if (getValue != null && getValue is DependencyObject)

                                getValue = Clone((DependencyObject)getValue);

                            // add item to collection

                            curPropInfo.ReflectedType.GetMethod("Add").Invoke(cloned, new object[] { getValue });

                        }

                    }

                }

            }



            return cloned;

        }

    }


}
